<?php

declare(strict_types=1);

namespace App;

use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;

class SimpleGateway
{
    private Server $server;
    
    public function __construct()
    {
        $this->server = new Server('0.0.0.0', 8080);
        $this->setupCallbacks();
    }
    
    private function setupCallbacks(): void
    {
        $this->server->on('request', [$this, 'onRequest']);
        $this->server->on('start', [$this, 'onStart']);
    }
    
    public function onStart(Server $server): void
    {
        echo "Gateway server started on http://0.0.0.0:8080\n";
    }
    
    public function onRequest(Request $request, Response $response): void
    {
        $path = $request->server['request_uri'] ?? '/';
        $method = $request->server['request_method'] ?? 'GET';
        
        // 调试信息
        error_log("Gateway request: $method $path");
        
        // 设置 CORS 头
        $response->header('Access-Control-Allow-Origin', '*');
        $response->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
        $response->header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
        $response->header('Content-Type', 'application/json');
        
        // 处理 OPTIONS 请求
        if ($method === 'OPTIONS') {
            $response->status(200);
            $response->end();
            return;
        }
        
        try {
            $result = $this->handleRequest($path, $method, $request);
            $response->status(200);
            $response->end(json_encode($result, JSON_UNESCAPED_UNICODE));
        } catch (\Exception $e) {
            $response->status(500);
            $response->end(json_encode([
                'error' => 'Internal Server Error',
                'message' => $e->getMessage()
            ], JSON_UNESCAPED_UNICODE));
        }
    }
    
    private function handleRequest(string $path, string $method, Request $request): array
    {
        // 网关信息
        if ($path === '/' || $path === '/gateway') {
            return [
                'message' => 'Hyperf Microservice Gateway',
                'version' => '1.0.0',
                'description' => 'HTTP Gateway for Microservice RPC Calls',
                'services' => [
                    'notice' => 'hyperf_notice_local:9501',
                    'data' => 'hyperf_data_local:9509',
                    'nacos' => 'nacos:8848',
                ],
                'endpoints' => [
                    'GET /gateway' => 'Gateway info',
                    'GET /gateway/health' => 'Health check',
                    'GET /gateway/api/notice/*' => 'Proxy to notice service',
                    'GET /gateway/api/data/*' => 'Proxy to data service',
                ]
            ];
        }
        
        // 健康检查
        if ($path === '/gateway/health') {
            return [
                'status' => 'healthy',
                'services' => [
                    'notice' => $this->checkService('http://hyperf_notice_local:9501/'),
                    'data' => $this->checkService('http://hyperf_data_local:9509/'),
                    'nacos' => $this->checkService('http://nacos:8848/nacos/'),
                ],
                'timestamp' => date('Y-m-d H:i:s'),
            ];
        }
        
        // 代理到 Notice 服务
        if (strpos($path, '/gateway/api/notice/') === 0) {
            $targetPath = substr($path, strlen('/gateway/api/notice/'));
            return $this->proxyToNotice($targetPath, $method, $request);
        }
        
        // 处理 Data 服务 RPC 调用
        if ($path === '/gateway/api/data/rpc' && $method === 'POST') {
            return $this->handleDataRpc($request);
        }
        
        // 代理到 Data 服务
        if (strpos($path, '/gateway/api/data/') === 0) {
            $targetPath = substr($path, strlen('/gateway/api/data/'));
            return $this->proxyToData($targetPath, $method, $request);
        }
        
        return [
            'error' => 'Not Found',
            'message' => 'Endpoint not found',
            'path' => $path
        ];
    }
    
    private function proxyToNotice(string $path, string $method, Request $request): array
    {
        $url = 'http://hyperf_notice_local:9501/' . $path;
        
        if ($method === 'GET' && !empty($request->get)) {
            $url .= '?' . http_build_query($request->get);
        }
        
        return $this->makeHttpRequest($url, $method, $request->getContent());
    }
    
    private function proxyToData(string $path, string $method, Request $request): array
    {
        $url = 'http://hyperf_data_local:9509/' . $path;
        
        if ($method === 'GET' && !empty($request->get)) {
            $url .= '?' . http_build_query($request->get);
        }
        
        return $this->makeHttpRequest($url, $method, $request->getContent());
    }
    
    private function makeHttpRequest(string $url, string $method, string $body = ''): array
    {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
        ]);
        
        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            if ($body) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
            }
        }
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        if ($error) {
            throw new \Exception("HTTP request failed: $error");
        }
        
        $data = json_decode($response, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            return [
                'status' => 'success',
                'raw_response' => $response,
                'http_code' => $httpCode
            ];
        }
        
        return $data;
    }
    
    private function handleDataRpc(Request $request): array
    {
        $rpcRequest = [
            'jsonrpc' => '2.0',
            'method' => 'data/getCampuses',
            'params' => [['requestId' => 'gateway-test-' . uniqid()]],
            'id' => 1
        ];

        $url = 'http://hyperf_data_local:9509/';
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($rpcRequest));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Json-Rpc: 2.0',
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        if ($error) {
            throw new \Exception("HTTP request failed: $error");
        }
        
        $data = json_decode($response, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            return [
                'status' => 'error',
                'message' => 'Invalid JSON response',
                'raw_response' => $response
            ];
        }
        
        return [
            'status' => 'success',
            'service' => 'data',
            'method' => 'rpc',
            'request' => $rpcRequest,
            'response' => $data,
            'timestamp' => date('Y-m-d H:i:s'),
        ];
    }
    
    private function checkService(string $url): bool
    {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
        curl_setopt($ch, CURLOPT_NOBODY, true);
        
        $result = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        return $result !== false && $httpCode < 500;
    }
    
    public function start(): void
    {
        $this->server->start();
    }
}
